package de.tu_darmstadt.gdi1.xcom.tests.testcases.students;

import static org.junit.Assert.assertEquals;

import java.util.regex.Pattern;

import org.junit.Before;
import org.junit.Test;

import de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel2;

/**
 * 
 * Tests if savegames are correctly interpreted
 * 
 * @author Lukas Schwoebel
 *
 */
public class SavegameTest {
	
	private XcomTestAdapterLevel2 testAdapter;
	
	
	/**
	 * @throws java.lang.Exception
	 */
	@Before
	public void setUp() throws Exception {
		testAdapter = new XcomTestAdapterLevel2();
	}

	/**
	 * Test method for {@link de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1#loadLevelFromString()}.
	 */
	@Test
	public final void testSaveGameloaded() {
		
		// load savegame
		testAdapter.loadLevelFromString(TestLevel.saveGame1);
		
		// now check for the players if data was interpreted correctly
		testAdapter.changeActivePlayer(4, 2);
		assertEquals("After loading the savegame, player at 4:2 should have only 40 healthpoints", 40, testAdapter.healthPointsLeft());
		testAdapter.changeActivePlayer(2, 5);
		assertEquals("After loading the savegame, player at 2:5 should have 60 actionpoints left", 60, testAdapter.actionPointsLeft());
		testAdapter.changeActivePlayer(4, 6);
		assertEquals("After loading the savegame, player at 4:6 should look south", 3, testAdapter.activePlayerLookingToDirection());

		assertEquals("After loading the savegame, there should only be 2 turns left", 2, testAdapter.turnsLeft());
		

		// remove any additional info at the end of the savegame
		String returnedSavegame = testAdapter.returnGamestateAsSavegame();
		// replace doors-line if there is any and remove any additional info if there is any
		returnedSavegame = returnedSavegame.replaceFirst("(?m)//\\{doors\\}\n", "");
		returnedSavegame = returnedSavegame.replaceFirst("(?s)//maxrounds:2(.*)$", "//maxrounds:2");
		
		// now check if the produced savegame equals the original savegame
		assertEquals("The produced savegame should be equal to the loaded savegame", TestLevel.saveGame1, returnedSavegame);
	}

	/**
	 * Test method for {@link de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel2#returnGamestateAsSavegame()}.
	 */
	@Test
	public final void testSaveGameCreated() {
		
		// load the given savegame
		testAdapter.loadLevelFromString(TestLevel.saveGame1);
		
		// do some actions with the players
		
		testAdapter.changeActivePlayer(4, 2);
		testAdapter.rotateActivePlayer(false);
		testAdapter.rotateActivePlayer(false);
		testAdapter.performActionForActivePlayer(); // attack alien, dont kill it
		
		testAdapter.changeActivePlayer(2, 1);
		testAdapter.rotateActivePlayer(true);
		testAdapter.rotateActivePlayer(true);
		
		testAdapter.changeActivePlayer(2, 5);
		testAdapter.performActionForActivePlayer();
		
		// now create savegame
		String saveGame = testAdapter.returnGamestateAsSavegame();
		
		String expectedSavegame = "" +
			"############\n" +
			"##...#######\n" +
			"##...##...##\n" +
			"###.###...##\n" +
			"###.####.###\n" +
			"#....##...##\n" +
			"#.........##\n" +
			"############\n" +
			"//{mobs}\n" +
			"//@;2;1;s;1;10;50;50;10\n" +
			"//@;4;2;w;40;63;34;49;8\n" +
			"//@;1;5;w;30;57;50;50;11\n" +
			"//@;4;6;s;50;75;50;50;3\n" +
			"//Z;2;2;e;50;75;50;0;0\n" +
			"//Z;3;2;n;16;75;50;0;0\n" +
			"//Z;7;3;n;50;75;50;0;0\n" +
			"//Z;7;5;n;50;75;50;0;0\n" +
			"//Z;9;6;n;50;75;50;0;0\n" +
			TestLevel.saveGame1Gamestate1;
		
		// replace doors-line if there is any and remove any additional info if there is any
		saveGame = saveGame.replaceFirst("(?m)//\\{doors\\}\n", "");
		saveGame = saveGame.replaceFirst("(?s)//maxrounds:2(.*)$", "//maxrounds:2");
		
		assertEquals("The created savegame was not equal to the expected one.", expectedSavegame, saveGame);	
	}
	
	/**
	 * Test method for {@link de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1#loadLevelFromString()}.
	 */
	@Test
	public final void testRoundsLeftInSavegame() {
		
		// load savegame
		testAdapter.loadLevelFromString(TestLevel.saveGame1);
				
		// do some actions
		testAdapter.changeActivePlayer(4, 2);
		testAdapter.rotateActivePlayer(true);
		testAdapter.rotateActivePlayer(true);
		testAdapter.performActionForActivePlayer();
		
		testAdapter.changeActivePlayer(2, 1);
		testAdapter.rotateActivePlayer(true);
		testAdapter.performActionForActivePlayer();
		
		assertEquals("After loading the savegame and performing some actions, still 2 turns should be left", 2, testAdapter.turnsLeft());
		
		// now create savegame and load this savegame
		testAdapter.loadLevelFromString(testAdapter.returnGamestateAsSavegame());
		
		assertEquals("After creating a savegame and loading this one, still 2 turns should be left", 2, testAdapter.turnsLeft());
	}

	/**
	 * Test method for {@link de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1#loadLevelFromString()}.
	 */
	@Test
	public final void testEqualSavegames() {
		
		// load savegame
		testAdapter.loadLevelFromString(TestLevel.saveGame1);
		
		// now create and load a savegame at the same time
		testAdapter.loadLevelFromString(testAdapter.returnGamestateAsSavegame());
		
		// remove any additional info at the end of the savegame
		String returnedSavegame = testAdapter.returnGamestateAsSavegame();
		// replace doors-line if there is any and remove any additional info if there is any
		returnedSavegame = returnedSavegame.replaceFirst("(?m)//\\{doors\\}\n", "");
		returnedSavegame = returnedSavegame.replaceFirst("(?s)//maxrounds:2(.*)$", "//maxrounds:2");
		
		// now check if savegame is still the same
		assertEquals("No action was performed, so the created savegame should be the same after loading it twice", TestLevel.saveGame1, returnedSavegame);
	}
}
